package com.xin.di.uav.utils;

import com.google.gson.annotations.SerializedName;
//import com.java.utils.WXPayUtility; // 引用微信支付工具库 参考:https://pay.weixin.qq.com/doc/v3/merchant/4014931831

import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 退款申请
 */
@Component
public class WechatRefundUtils {
    private static String HOST = "https://api.mch.weixin.qq.com";
    private static String METHOD = "POST";
    private static String PATH = "/v3/refund/domestic/refunds";

    @Value("${wx.key-path:D:\\1727006153_20250909_cert\\apiclient_key.pem}")
    private String KEY_PATH;

    @Value("${wx.pub-key-path:D:\\1727006153_20250909_cert\\pub_key.pem}")
    private String pubKeyPath;

    private String mchId = "1727006153";

    private String certificateSerialNo = "1a0d73e8bd8f023d56afee6eb6d028f7a9068b97";
    private String wechatPayPublicKeyId = "5Z9A4Gr12Y549Xd73E2Tr45T3EBV678p";

    public Refund refund(CreateRequest request) {
        // TODO: 请准备商户开发必要参数，参考：https://pay.weixin.qq.com/doc/v3/merchant/4013070756

        try {
            // TODO: 请求成功，继续业务逻辑
            return this.run(request);
        } catch (WXPayUtility.ApiException e) {
            // TODO: 请求失败，根据状态码执行不同的逻辑
            e.printStackTrace();
        }
        return null;
    }

    public Refund run(CreateRequest request) {

        PrivateKey privateKey = WXPayUtility.loadPrivateKeyFromPath(KEY_PATH);
//
//        PublicKey wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(pubKeyPath);

        String uri = PATH;
        String reqBody = WXPayUtility.toJson(request);

        Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
        reqBuilder.addHeader("Accept", "application/json");
        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, certificateSerialNo, privateKey, METHOD, uri, reqBody));
        reqBuilder.addHeader("Content-Type", "application/json");
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
        reqBuilder.method(METHOD, requestBody);
        Request httpRequest = reqBuilder.build();

        // 发送HTTP请求
        OkHttpClient client = new OkHttpClient.Builder().build();
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            String respBody = WXPayUtility.extractBody(httpResponse);
            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
                // 2XX 成功，验证应答签名
//                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
//                        httpResponse.headers(), respBody);

                // 从HTTP应答报文构建返回数据
                return WXPayUtility.fromJson(respBody, Refund.class);
            } else {
                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
        }
    }


    public enum Status {
        @SerializedName("SUCCESS")
        SUCCESS,
        @SerializedName("CLOSED")
        CLOSED,
        @SerializedName("PROCESSING")
        PROCESSING,
        @SerializedName("ABNORMAL")
        ABNORMAL
    }

    public enum Account {
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNAVAILABLE")
        UNAVAILABLE
    }

    public enum PromotionType {
        @SerializedName("COUPON")
        COUPON,
        @SerializedName("DISCOUNT")
        DISCOUNT
    }

    public static class GoodsDetail {
        @SerializedName("merchant_goods_id")
        public String merchantGoodsId;

        @SerializedName("wechatpay_goods_id")
        public String wechatpayGoodsId;

        @SerializedName("goods_name")
        public String goodsName;

        @SerializedName("unit_price")
        public Long unitPrice;

        @SerializedName("refund_amount")
        public Long refundAmount;

        @SerializedName("refund_quantity")
        public Integer refundQuantity;
    }

    public static class CreateRequest {
        @SerializedName("transaction_id")
        public String transactionId;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("out_refund_no")
        public String outRefundNo;

        @SerializedName("reason")
        public String reason;

        @SerializedName("notify_url")
        public String notifyUrl;

        @SerializedName("funds_account")
        public ReqFundsAccount fundsAccount;

        @SerializedName("amount")
        public AmountReq amount;

        @SerializedName("goods_detail")
        public List<GoodsDetail> goodsDetail;
    }

    public enum Channel {
        @SerializedName("ORIGINAL")
        ORIGINAL,
        @SerializedName("BALANCE")
        BALANCE,
        @SerializedName("OTHER_BALANCE")
        OTHER_BALANCE,
        @SerializedName("OTHER_BANKCARD")
        OTHER_BANKCARD
    }

    public static class Amount {
        @SerializedName("total")
        public Long total;

        @SerializedName("refund")
        public Long refund;

        @SerializedName("from")
        public List<FundsFromItem> from;

        @SerializedName("payer_total")
        public Long payerTotal;

        @SerializedName("payer_refund")
        public Long payerRefund;

        @SerializedName("settlement_refund")
        public Long settlementRefund;

        @SerializedName("settlement_total")
        public Long settlementTotal;

        @SerializedName("discount_refund")
        public Long discountRefund;

        @SerializedName("currency")
        public String currency;

        @SerializedName("refund_fee")
        public Long refundFee;
    }

    public enum ReqFundsAccount {
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNSETTLED")
        UNSETTLED
    }

    public enum FundsAccount {
        @SerializedName("UNSETTLED")
        UNSETTLED,
        @SerializedName("AVAILABLE")
        AVAILABLE,
        @SerializedName("UNAVAILABLE")
        UNAVAILABLE,
        @SerializedName("OPERATION")
        OPERATION,
        @SerializedName("BASIC")
        BASIC,
        @SerializedName("ECNY_BASIC")
        ECNY_BASIC
    }

    public static class Promotion {
        @SerializedName("promotion_id")
        public String promotionId;

        @SerializedName("scope")
        public PromotionScope scope;

        @SerializedName("type")
        public PromotionType type;

        @SerializedName("amount")
        public Long amount;

        @SerializedName("refund_amount")
        public Long refundAmount;

        @SerializedName("goods_detail")
        public List<GoodsDetail> goodsDetail;
    }

    public static class Refund {
        @SerializedName("refund_id")
        public String refundId;

        @SerializedName("out_refund_no")
        public String outRefundNo;

        @SerializedName("transaction_id")
        public String transactionId;

        @SerializedName("out_trade_no")
        public String outTradeNo;

        @SerializedName("channel")
        public Channel channel;

        @SerializedName("user_received_account")
        public String userReceivedAccount;

        @SerializedName("success_time")
        public String successTime;

        @SerializedName("create_time")
        public String createTime;

        @SerializedName("status")
        public Status status;

        @SerializedName("funds_account")
        public FundsAccount fundsAccount;

        @SerializedName("amount")
        public Amount amount;

        @SerializedName("promotion_detail")
        public List<Promotion> promotionDetail;
    }

    public static class FundsFromItem {
        @SerializedName("account")
        public Account account;

        @SerializedName("amount")
        public Long amount;
    }

    public static class AmountReq {
        @SerializedName("refund")
        public Long refund;

        @SerializedName("from")
        public List<FundsFromItem> from;

        @SerializedName("total")
        public Long total;

        @SerializedName("currency")
        public String currency;
    }

    public enum PromotionScope {
        @SerializedName("GLOBAL")
        GLOBAL,
        @SerializedName("SINGLE")
        SINGLE
    }
}
